Imports Runa.Scripting
Imports System.IO.IsolatedStorage
Imports System.Windows.Forms
Imports Runa.Core.Runtime
Imports Runa.Core.ResourceManager
Imports Runa.Core.Extension

''' <summary>
''' This is the main type for your game
''' </summary>
Public Class GameRenderForWindows
    Inherits Microsoft.Xna.Framework.Game

    Private m_gameName As String
    Private m_gameParser As GameParser
    Private m_gameLoaded As Boolean = False

    Private m_scriptInitialization As ScriptTask
    Private m_scriptOnShowingLoadingPage As ScriptTask
    Private m_scriptOnLoadingContents As ScriptTask
    Private m_scriptOnDraw As ScriptTask
    Private m_scriptOnUpdate As ScriptTask
    Private m_scriptOnBackKeyPress As ScriptTask

    Private contentManager As IsolatedContentManager

    Private WithEvents graphics As GraphicsDeviceManager
    Private WithEvents spriteBatch As SpriteBatch

    Public Sub New()
        graphics = New GraphicsDeviceManager(Me)
    End Sub

    Public Sub New(ByVal name As String)
        graphics = New GraphicsDeviceManager(Me)
        Me.m_gameName = name
    End Sub

    ''' <summary>
    ''' Binding the OnError event to one event rountine.
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub BindingScriptTaskOnErrorEvent()
        AddHandler Me.m_scriptOnLoadingContents.OnError, AddressOf ScriptTask_OnError
        AddHandler Me.m_scriptOnDraw.OnError, AddressOf ScriptTask_OnError
        AddHandler Me.m_scriptOnUpdate.OnError, AddressOf ScriptTask_OnError
        AddHandler Me.m_scriptOnBackKeyPress.OnError, AddressOf ScriptTask_OnError
    End Sub

    ''' <summary>
    ''' Handles OnError events of all the ScriptTask objects.
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub ScriptTask_OnError(ByVal sender As Object, ByVal e As ScriptTaskOnErrorEventArgs)
        MessageBox.Show(String.Format("Script {0} Error: {1}", CType(sender, ScriptTask).Name, e.Error.Message & vbCrLf & e.Error.StackTrace.ToString()))
    End Sub

    ''' <summary>
    ''' Allows the game to perform any initialization it needs to before starting to run.
    ''' This is where it can query for any required services and load any non-graphic
    ''' related content.  Calling MyBase.Initialize will enumerate through any components
    ''' and initialize them as well.
    ''' </summary>
    Protected Overrides Sub Initialize()
        ' TODO: Add your initialization logic here
        Me.m_gameParser = g_gameList.Where(Function(obj) obj.Name = Me.m_gameName)(0)

        Dim oldResolution As New Vector2
        With Me.m_gameParser
            graphics.TryChangeResolution(New Vector2(.WindowWidth, .WindowHeight), oldResolution)
        End With

        Me.contentManager = New IsolatedContentManager(Content.ServiceProvider, m_gameParser.GameContentRoot, fileStorage)
        Me.spriteBatch = New SpriteBatch(GraphicsDevice)
        Me.Content = Me.contentManager

        ' Initialize the ScriptTask object for Initialization()
        Me.m_scriptInitialization = New ScriptTask("Initialization.rb")
        AddHandler Me.m_scriptInitialization.OnError, AddressOf Me.ScriptTask_OnError
        m_scriptInitialization.LoadScriptFromIsolatedStorage(IO.Path.Combine(Me.contentManager.IsolatedStorageRootDirectory, "Initialization.rb"), fileStorage)

        Me.m_scriptInitialization.LoadAssembly(Me.m_gameParser.GetType().Assembly)
        Me.m_scriptInitialization.LoadAssembly(GetType(SpriteFont).Assembly)
        Me.m_scriptInitialization.LoadAssembly(GetType(SpriteBatch).Assembly)
        Me.m_scriptInitialization.LoadAssembly(GetType(GraphicsDevice).Assembly)
        Me.m_scriptInitialization.LoadAssembly(GetType(Texture2D).Assembly)
        Me.m_scriptInitialization.LoadAssembly(GetType(Vector2).Assembly)

        Me.m_scriptInitialization.LoadAssembly(GetType(FontObject).Assembly)
        Me.m_scriptInitialization.LoadAssembly(GetType(Texture2DObject).Assembly)
        Me.m_scriptInitialization.LoadAssembly(GetType(AudioObject).Assembly)

        m_scriptInitialization.Excute( _
            New Tuple(Of String, Object)("ThisGameParser", Me.m_gameParser), _
            New Tuple(Of String, Object)("PhonePage", Me), _
            New Tuple(Of String, Object)("ContentManager", Me.contentManager), _
            New Tuple(Of String, Object)("CurrentGraphicsDevice", GraphicsDevice))

        ' Initialize the ScriptTask object for OnDraw.OnShowingLoadingPage()
        Me.m_scriptOnShowingLoadingPage = New ScriptTask("OnShowingLoadingPage.rb")
        m_scriptOnShowingLoadingPage.LoadScriptFromIsolatedStorage(IO.Path.Combine(Me.contentManager.IsolatedStorageRootDirectory, "OnShowingLoadingPage.rb"), fileStorage)

        Me.m_scriptOnShowingLoadingPage.LoadAssembly(Me.m_gameParser.GetType().Assembly)
        Me.m_scriptOnShowingLoadingPage.LoadAssembly(GetType(SpriteFont).Assembly)
        Me.m_scriptOnShowingLoadingPage.LoadAssembly(GetType(SpriteBatch).Assembly)
        Me.m_scriptOnShowingLoadingPage.LoadAssembly(GetType(GraphicsDevice).Assembly)
        Me.m_scriptOnShowingLoadingPage.LoadAssembly(GetType(Vector2).Assembly)
        Me.m_scriptOnShowingLoadingPage.LoadAssembly(GetType(Texture2D).Assembly)
        Me.m_scriptOnShowingLoadingPage.LoadAssembly(GetType(GameTime).Assembly)

        Me.m_scriptOnShowingLoadingPage.LoadAssembly(GetType(FontObject).Assembly)
        Me.m_scriptOnShowingLoadingPage.LoadAssembly(GetType(Texture2DObject).Assembly)
        Me.m_scriptOnShowingLoadingPage.LoadAssembly(GetType(AudioObject).Assembly)

        MyBase.Initialize()
    End Sub

    ''' <summary>
    ''' LoadContent will be called once per game and is the place to load
    ''' all of your content.
    ''' </summary>
    Protected Overrides Sub LoadContent()
        ' TODO: use Me.Content to load your game content here
        Dim thr As New Threading.Thread(
            Sub()
                ' Initialize the ScriptTask object for LoadContent()
                Me.m_scriptOnLoadingContents = New ScriptTask("OnLoadingContents.rb")
                m_scriptOnLoadingContents.LoadScriptFromIsolatedStorage(IO.Path.Combine(Me.contentManager.IsolatedStorageRootDirectory, "OnLoadingContents.rb"), fileStorage)

                Me.m_scriptOnLoadingContents.LoadAssembly(Me.m_gameParser.GetType().Assembly)
                Me.m_scriptOnLoadingContents.LoadAssembly(GetType(SpriteFont).Assembly)
                Me.m_scriptOnLoadingContents.LoadAssembly(GetType(SpriteBatch).Assembly)
                Me.m_scriptOnLoadingContents.LoadAssembly(GetType(GraphicsDevice).Assembly)
                Me.m_scriptOnLoadingContents.LoadAssembly(GetType(Texture2D).Assembly)
                Me.m_scriptOnLoadingContents.LoadAssembly(GetType(Vector2).Assembly)

                Me.m_scriptOnLoadingContents.LoadAssembly(GetType(FontObject).Assembly)
                Me.m_scriptOnLoadingContents.LoadAssembly(GetType(Texture2DObject).Assembly)
                Me.m_scriptOnLoadingContents.LoadAssembly(GetType(AudioObject).Assembly)

                ' Initialize the ScriptTask object for OnDraw()
                Me.m_scriptOnDraw = New ScriptTask("OnDraw.rb")
                m_scriptOnDraw.LoadScriptFromIsolatedStorage(IO.Path.Combine(Me.contentManager.IsolatedStorageRootDirectory, "OnDraw.rb"), fileStorage)

                Me.m_scriptOnDraw.LoadAssembly(Me.m_gameParser.GetType().Assembly)
                Me.m_scriptOnDraw.LoadAssembly(GetType(SpriteFont).Assembly)
                Me.m_scriptOnDraw.LoadAssembly(GetType(SpriteBatch).Assembly)
                Me.m_scriptOnDraw.LoadAssembly(GetType(GraphicsDevice).Assembly)
                Me.m_scriptOnDraw.LoadAssembly(GetType(Vector2).Assembly)
                Me.m_scriptOnDraw.LoadAssembly(GetType(Texture2D).Assembly)
                Me.m_scriptOnDraw.LoadAssembly(GetType(GameTime).Assembly)

                Me.m_scriptOnDraw.LoadAssembly(GetType(FontObject).Assembly)
                Me.m_scriptOnDraw.LoadAssembly(GetType(Texture2DObject).Assembly)
                Me.m_scriptOnDraw.LoadAssembly(GetType(AudioObject).Assembly)

                ' Initialize the ScriptTask object for OnUpdate()
                Me.m_scriptOnUpdate = New ScriptTask("OnUpdate.rb")
                m_scriptOnUpdate.LoadScriptFromIsolatedStorage(IO.Path.Combine(Me.contentManager.IsolatedStorageRootDirectory, "OnUpdate.rb"), fileStorage)

                Me.m_scriptOnUpdate.LoadAssembly(Me.m_gameParser.GetType().Assembly)
                Me.m_scriptOnUpdate.LoadAssembly(GetType(SpriteFont).Assembly)
                Me.m_scriptOnUpdate.LoadAssembly(GetType(SpriteBatch).Assembly)
                Me.m_scriptOnUpdate.LoadAssembly(GetType(GraphicsDevice).Assembly)
                Me.m_scriptOnUpdate.LoadAssembly(GetType(Vector2).Assembly)
                Me.m_scriptOnUpdate.LoadAssembly(GetType(Texture2D).Assembly)
                Me.m_scriptOnUpdate.LoadAssembly(GetType(GamePad).Assembly)
                Me.m_scriptOnUpdate.LoadAssembly(GetType(GameTime).Assembly)

                Me.m_scriptOnUpdate.LoadAssembly(GetType(FontObject).Assembly)
                Me.m_scriptOnUpdate.LoadAssembly(GetType(Texture2DObject).Assembly)
                Me.m_scriptOnUpdate.LoadAssembly(GetType(AudioObject).Assembly)

                ' Initialize the ScriptTask object for OnBackKeyPress()
                Me.m_scriptOnBackKeyPress = New ScriptTask("OnBackKeyPress.rb")
                m_scriptOnBackKeyPress.LoadScriptFromIsolatedStorage(IO.Path.Combine(Me.contentManager.IsolatedStorageRootDirectory, "OnBackKeyPress.rb"), fileStorage)

                Me.m_scriptOnBackKeyPress.LoadAssembly(Me.m_gameParser.GetType().Assembly)
                Me.m_scriptOnBackKeyPress.LoadAssembly(GetType(SpriteFont).Assembly)
                Me.m_scriptOnBackKeyPress.LoadAssembly(GetType(SpriteBatch).Assembly)
                Me.m_scriptOnBackKeyPress.LoadAssembly(GetType(GraphicsDevice).Assembly)
                Me.m_scriptOnBackKeyPress.LoadAssembly(GetType(Vector2).Assembly)
                Me.m_scriptOnBackKeyPress.LoadAssembly(GetType(Texture2D).Assembly)
                Me.m_scriptOnBackKeyPress.LoadAssembly(GetType(GamePad).Assembly)
                Me.m_scriptOnBackKeyPress.LoadAssembly(GetType(GameTime).Assembly)
                Me.m_scriptOnBackKeyPress.LoadAssembly(GetType(MessageBox).Assembly)

                Me.m_scriptOnBackKeyPress.LoadAssembly(GetType(FontObject).Assembly)
                Me.m_scriptOnBackKeyPress.LoadAssembly(GetType(Texture2DObject).Assembly)
                Me.m_scriptOnBackKeyPress.LoadAssembly(GetType(AudioObject).Assembly)

                Call BindingScriptTaskOnErrorEvent()

                m_scriptOnLoadingContents.Excute( _
                    New Tuple(Of String, Object)("ThisGameParser", Me.m_gameParser), _
                    New Tuple(Of String, Object)("PhonePage", Me), _
                    New Tuple(Of String, Object)("ContentManager", Me.contentManager), _
                    New Tuple(Of String, Object)("CurrentGraphicsDevice", GraphicsDevice))

                Me.m_gameLoaded = True
            End Sub)
        thr.Start()
    End Sub

    ''' <summary>
    ''' UnloadContent will be called once per game and is the place to unload
    ''' all content.
    ''' </summary>
    Protected Overrides Sub UnloadContent()
        ' TODO: Unload any non ContentManager content here
    End Sub

    ''' <summary>
    ''' Allows the game to run logic such as updating the world,
    ''' checking for collisions, gathering input, and playing audio.
    ''' </summary>
    ''' <param name="gameTime">Provides a snapshot of timing values.</param>
    Protected Overrides Sub Update(ByVal gameTime As GameTime)
        ' Allows the game to exit
        If GamePad.GetState(PlayerIndex.One).Buttons.Back = Microsoft.Xna.Framework.Input.ButtonState.Pressed Then
            Me.Exit()
        End If

        ' TODO: Add your update logic here
        If Me.m_gameLoaded Then
            Dim gt As New GameTimeEventArgs(gameTime)
            Me.m_scriptOnUpdate.LoadAssembly(gt.GetType().Assembly)
            Me.m_scriptOnUpdate.Excute( _
                New Tuple(Of String, Object)("ThisGameParser", Me.m_gameParser), _
                New Tuple(Of String, Object)("PhonePage", Me), _
                New Tuple(Of String, Object)("GameTimerEventArg", gt), _
                New Tuple(Of String, Object)("CurrentGraphicsDevice", GraphicsDevice))
        End If

        MyBase.Update(gameTime)
    End Sub

    ''' <summary>
    ''' This is called when the game should draw itself.
    ''' </summary>
    ''' <param name="gameTime">Provides a snapshot of timing values.</param>
    Protected Overrides Sub Draw(ByVal gameTime As GameTime)
        ' TODO: Add your drawing code here
        Dim gt As New GameTimeEventArgs(gameTime)
        If Me.m_gameLoaded Then
            Me.m_scriptOnDraw.LoadAssembly(gt.GetType().Assembly)
            Me.m_scriptOnDraw.Excute( _
                New Tuple(Of String, Object)("ThisGameParser", Me.m_gameParser), _
                New Tuple(Of String, Object)("PhonePage", Me), _
                New Tuple(Of String, Object)("GameTimerEventArg", gt), _
                New Tuple(Of String, Object)("CurrentGraphicsDevice", GraphicsDevice))
        Else
            Me.m_scriptOnShowingLoadingPage.LoadAssembly(gt.GetType().Assembly)
            Me.m_scriptOnShowingLoadingPage.Excute( _
                New Tuple(Of String, Object)("ThisGameParser", Me.m_gameParser), _
                New Tuple(Of String, Object)("PhonePage", Me), _
                New Tuple(Of String, Object)("GameTimerEventArg", gt), _
                New Tuple(Of String, Object)("CurrentGraphicsDevice", GraphicsDevice))
        End If

        MyBase.Draw(gameTime)
    End Sub

End Class